home *** CD-ROM | disk | FTP | other *** search
/ stazsoftware.com / www.stazsoftware.com.tar / www.stazsoftware.com / futurebasic / sample-code / DBFD.sit / DBFD2.0 / DataBrowser With Toolbox / Hierarchical DataBrowser < prev    next >
Text File  |  2003-11-13  |  29KB  |  904 lines

  1.  
  2. '~'A
  3. '                       Runtime : Rntm Appearance.Incl
  4. '                           CPU : Carbon
  5. '                    CALL Req'd : Off
  6. '~'B
  7. '~Introduction
  8. /*
  9.      Hierarchical DataBrowser demo shows how to create a hierarchical
  10.      list for the DataBrowser control.
  11.  
  12.      If you are unfamiliar with that versatile control, go read the
  13.      introduction found in the Simple DataBrowser demo file, the
  14.      following will assume that you have read it already.
  15.  
  16.      This demo is based on the above mentioned introduction and
  17.      it will add the hierarchical navigation within the list of
  18.      items displayed in the DataBrowser.
  19.      In order to build our hierarchy we will perform a recursive
  20.      scan of the folder chosen by the end-user.
  21.  
  22. '~Building the hierarchy
  23.  
  24.      Obviously, the program must keep track of the item hierarchy,
  25.      that's why we will introduce another field in our custom
  26.      ItemRecord to hold the itemID of the parent item, said otherwise
  27.      the folder in which the item found is located.
  28.      We will also introduce another global variable that will help
  29.      for counting the items during the recursive search.
  30.  
  31.      The demo below adds also two new columns that will display the
  32.      creator code and the file type of the items found.
  33.  
  34. '~Displaying the hiearchical list
  35.  
  36.      There are three steps to follow in order to get the things
  37.      going:
  38.  
  39.      1) Setting the disclosure column
  40. '~'9
  41.         The fist step is to decide which column must contain the
  42.         disclosure triangle. Notice that you can dynamically
  43.         change that setting. This is done like so (propertyID
  44.         being the custom identifier for the column):
  45.  
  46.      err = FN SetDataBrowserListViewDisclosureColumn( browser, propertyID, _false )
  47.  
  48.  
  49.      2) Setting the container property
  50. '~'9
  51.         You must let the DataBrowser know which items are meant
  52.         to become containers that will possibly own subitems.
  53.         This is done when the DataBrowser asks you for information
  54.         within the GetSetItemData callback procedure. In the
  55.         DataBrowserPropertyID parameter that usually contains
  56.         the column identifier, the DataBrowser will pass the value
  57.         _kDataBrowserItemIsContainerProperty asking you if the
  58.         item under examination is a container or not. You must
  59.         answer with a boolean value using the following function:       
  60.  
  61.      err = FN SetDataBrowserItemDataBooleanValue( itemData, _true )
  62.  
  63.  
  64.      3) Showing the subitems
  65. '~'9
  66.         The last step involves another callback procedure that you
  67.         must install at the same time as your GetSetItemData callback,
  68.         that is right after the creation of the DataBrowser control.
  69.         This new procedure is called ItemNotification callback.
  70.         The DataBrowser will call that routine each time something
  71.         happens that might interest you, typically when the end-user
  72.         interacts with the items in the list.
  73.         A few parameters are sent to the routine: the browser that
  74.         notifies your program, the itemID of the concerned item and
  75.         a value indicating which event is reported. The message that
  76.         is relevant for our purpose here, is: _kDataBrowserContainerOpened
  77.         which indicates that the end-user has played with the disclosure
  78.         triangle to unfold the container's content. Finally, it
  79.         indicates for you that it is time to add the subitems with
  80.         the ordinary AddDataBrowserItems function like so:
  81.           
  82.      err = FN AddDataBrowserItems( browser,containerItemID, subItemCount, @arrayOfSubItemIDs(0), _kDataBrowserItemNoProperty )
  83.  
  84.         It is to note that the subitems are destroyed every time
  85.         a container item is closed.
  86.  
  87.      To explore further the DataBrowser features (like drag & drop,
  88.      contextual menu, help tags, etc.) see the demo Basic DataBrowser.
  89.      
  90.  
  91.                                                             Alain   May 2003
  92. */
  93. '~'6
  94.  
  95. Include "Tlbx ControlDefinitions.Incl"
  96.  
  97. Include "Util_Files.incl"
  98. Include "Tlbx Icons.Incl"
  99.  
  100. '~Toolbox Added Declarations
  101.  
  102. _kWindowInWindowMenuAttribute  = (1 << 27 )
  103. _kControlDataBrowserPart       = 24
  104.  
  105. Toolbox Fn SetAutomaticControlDragTrackingEnabledForWindow( WindowRef inWindow, Boolean inTracks) = OSStatus
  106. Toolbox Fn CFAllocatorGetDefault = CFAllocatorRef
  107.  
  108. '~Application Constants
  109.  
  110. Begin Enum
  111. _mainWnd         = 1
  112.  
  113. _myCreator       = _"DEMO"
  114. _myDataBrowser   = _"Brsr"
  115.  
  116. _nameColumnID    = _"name"
  117. _typeColumnID    = _"type"
  118. _creatorColumnID = _"crea"
  119.  
  120. _scrollBarWidth  = 16
  121. End Enum
  122.  
  123. _menuFile = 1
  124. Begin Enum 1
  125. _itemOpenFolder
  126. _
  127. _itemQuit
  128. End Enum
  129.  
  130. '~Application Globals
  131.  
  132. Begin Record ItemRecord
  133. Dim itemID   As Long
  134. Dim parent   As Long
  135. Dim spec     As FSSpec   
  136. Dim type     As OSType
  137. Dim creator  As OSType
  138. Dim dataLen  As Long
  139. Dim rsrcLen  As Long
  140. Dim cDate    As Long
  141. Dim mDate    As Long
  142. Dim flags    As Short
  143. Dim attrib   As Short
  144. End Record
  145.  
  146.  
  147. Begin Globals
  148.  
  149. Dim As Long       gFileIndex
  150. Dim Dynamic       gFiles(_maxInt) As ItemRecord
  151.  
  152. End Globals
  153.  
  154.  
  155. '~';
  156. '~-
  157. '~Utility Functions
  158. /*
  159.      Handy function that returns the maximum index in a dynamic array
  160. */
  161. Def Fn UBound(@P As ptr) = [P + _AutoXREFCurr] - 1
  162.  
  163. '~'1
  164. /*
  165.      This function returns the iconRef for a given file
  166. */
  167. Clear Local Mode
  168. Local Fn GetFileIcon( fSpec As .FSSpec, type As OSType )
  169. '~'9
  170. Dim @ iconH As IconRef
  171. Dim @ label As Int
  172. Dim   err   As OSErr
  173.  
  174. If fSpec Then err = Fn GetIconRefFromFile( #fSpec, iconH, label )
  175. Long If err != _noErr Or iconH = _nil
  176. Select type
  177. Case _"APPL" : type = _kGenericApplicationIcon
  178. Case _"fldr" : type = _kGenericFolderIcon
  179. Case else    : type = _kGenericDocumentIcon
  180. End Select
  181. err = Fn GetIconRef( _kOnSystemDisk, _kSystemIconsCreator, type, iconH )
  182. End If
  183.  
  184. End Fn = iconH
  185.  
  186.  
  187. /*
  188.      GetFolderDirID returns the dirID of a folder given its FSSpec
  189. */
  190. Clear Local Mode
  191. Local Fn GetFolderDirID( fldSpec As .FSSpec, canCreateFolder As Boolean )
  192. '~'9
  193. Dim @ dirID As Long
  194. Dim   fld   As FSSpec
  195. Dim   pb.108 //CInfoPBRec
  196.  
  197. Select Fn FSMakeFSSpec( fldSpec.vRefNum, fldSpec.parID, fldSpec.name, fld )
  198. Case _noErr
  199. pb.ioNamePtr&   = @fldSpec.name
  200. pb.ioVRefNum%   = fldSpec.vRefNum
  201. pb.ioDirID&     = fldSpec.parID
  202. If Fn PBGetCatInfoSync( pb ) then Exit Fn
  203. dirID = pb.ioDirID&
  204.  
  205. Case _fnfErr
  206. Long If canCreateFolder != _kDontCreateFolder
  207. Long If Fn FSpDirCreate( fld, _smCurrentScript, dirID ) != _noErr
  208. Exit Fn
  209. End If
  210. End If
  211. End Select
  212.  
  213. End Fn = dirID
  214.  
  215.  
  216. '~--
  217. '~Application Functions
  218.  
  219. '~'1
  220. /*
  221.      This function retrieves the browser reference from the window
  222.      in which it is located.
  223.      The browser reference has been saved has a window property.
  224.      You can store private properties with user interface elements
  225.      as your liking and retrieve them when you need them.
  226. */
  227. Clear Local
  228. Local Fn GetDataBrowserFromWindow( wRef As WindowRef )
  229. '~'9
  230.  
  231. Dim As OSStatus     err
  232. Dim As ControlRef @ browser
  233.  
  234. Long If wRef
  235. err = Fn GetWindowProperty( wRef, _myCreator, _myDataBrowser, Sizeof(browser), #_nil, browser )
  236. End If
  237.  
  238. End Fn = browser
  239.  
  240.  
  241.  
  242. '~';
  243. /*
  244.      This function will resize the DataBrowser when needed,
  245.      for example, when the window is resized.
  246. */
  247. Clear Local Fn RefreshDataBrowser( wNum As Long )
  248. '~'9
  249. Dim As Rect         r
  250. Dim As WindowRef  @ wRef
  251. Dim As ControlRef   browser
  252.  
  253. Get Window wNum, wRef
  254. Long If wRef
  255. Long If Fn GetWindowBounds( wRef, _kWindowContentRgn, r ) = _noErr
  256. browser = Fn GetDataBrowserFromWindow( wRef )
  257. Long If browser
  258. SizeControl( browser, r.right - r.left, r.bottom - r.top)
  259. End If
  260. End If
  261. End If
  262.  
  263. End Fn
  264.  
  265.  
  266. /*
  267.      This function empties the DataBrowser
  268. */
  269. Clear Local
  270. Local Fn ClearDataBrowser
  271. '~'9
  272.  
  273. Dim As ControlRef   browser
  274. Dim As Handle       arrayOfItemID
  275. Dim As OSStatus     err
  276.  
  277. browser = Fn GetDataBrowserFromWindow( Window( _wndRef ) )
  278. If browser == _nil then Exit Fn
  279. /*
  280.      Below is another way to get all the itemIDs removed from the
  281.      DataBrowser list.
  282.      We ask first the DataBrowser to provide a flatten list of all the itemIDs
  283.      it contains. It will return that list in an handle that we must
  284.      supply (as an empty handle). The parmeter set to true in the
  285.      GetDataBrowserItems function means a recursive search.
  286.      On return we can use that list to remove all the itemIDs at once.
  287. */
  288. arrayOfItemID = Fn NewHandle( 0 )
  289. Long If arrayOfItemID
  290. err = Fn GetDataBrowserItems ( browser, _kDataBrowserNoItem, _true , _kDataBrowserItemAnyState, arrayOfItemID )
  291. Long If err = _noErr
  292. err = Fn RemoveDataBrowserItems ( browser,0, Fn GetHandleSize(arrayOfItemID)\\ Sizeof(DataBrowserItemID), #[arrayOfItemID], _nil)
  293. End If
  294. DisposeHandle( arrayOfItemID )// free the memory used
  295. End If
  296.  
  297. End Fn
  298.  
  299.  
  300. /*
  301.      This function installs the itemIDs in the DataBrowser control
  302. */
  303. Clear Local
  304. Local Fn FillDataBrowser
  305. '~'9
  306. Dim As ControlRef           browser
  307. Dim As OSStatus             err
  308. Dim As Long                 numberOfItems, u
  309. Dim As Handle               arrayOfItemID
  310.  
  311. browser = Fn GetDataBrowserFromWindow( Window( _wndRef ) )// retrieve the browser from the window property
  312. If browser == _nil then Exit Fn
  313.  
  314. numberOfItems = Fn UBound(gFiles)// retrieve the maximum index of our dynamic array
  315. If numberOfItems = 0 then Exit Fn// no items we can leave
  316.  
  317. arrayOfItemID = Fn NewHandle( 0 )// prepare the array (we will use here a handle)
  318.  
  319. For u = 2 To numberOfItems// we skip index 1 (which is the folder chosen by the end user)
  320. Long If gFiles.parent(u) = gFiles.itemID(1)// we will include only the items that belong to the master folder
  321. Long If Fn PtrAndHand( @gFiles.ItemID(u), arrayOfItemID, Sizeof(DataBrowserItemID) ) != _noErr
  322. DisposeHandle( arrayOfItemID ) : Exit Fn// leave the fn on error
  323. End If
  324. End If
  325. Next
  326.  
  327. err = Fn AddDataBrowserItems( browser, _kDataBrowserNoItem, Fn GetHandleSize(arrayOfItemID)\\ Sizeof(DataBrowserItemID), #[arrayOfItemID], _kDataBrowserItemNoProperty )
  328. DisposeHandle( arrayOfItemID )// free the memory used
  329. // make sure our itemID 2 (actually our first item in the list) is visible on screen
  330. err = Fn RevealDataBrowserItem ( browser, 2, _nameColumnID, _kDataBrowserRevealWithoutSelecting )
  331.  
  332. End Fn
  333.  
  334. '~'1
  335. /*
  336.      This function scans the folder specified by its FSSpec.
  337.      As it calls itself for a recursive search, an index is used
  338.      to keep track of who was calling the function (parentFolder)
  339. */
  340. Clear Local Fn CollectFileItems ( fSpec As .FSSpec, parentFolder As Long )
  341. '~'9
  342.  
  343. Dim As Short  Index, Err
  344. Dim As FSSpec tpSpec
  345. Dim           pb.128
  346.  
  347. #If Ndef _kFolderBit
  348. _kFolderBit = 3
  349. #Endif
  350.  
  351. Index = 1// start at index 1
  352.  
  353. Do
  354.  
  355. pb.ioFDirIndex%  = Index// fill the param block
  356. pb.ioNamePtr&    = @fSpec.name// the folder requested
  357. pb.ioVRefNum%    = fSpec.vRefNum
  358. pb.ioDirID&      = fSpec.parID
  359.  
  360. If Fn PBGetCatInfoSync( pb ) then Exit Do// leave the loop on error
  361.  
  362.  
  363. Long If ( pb.ioFlUsrWds.fdFlags% And _fInvisible ) = _false// skip invisible items
  364. gFileIndex++// we've got one more item to add to our list
  365. gFiles.itemID(gFileIndex) = gFileIndex// this index will become our DataBrowser itemID
  366. gFiles.parent(gFileIndex) = parentFolder// store the parent folder index in the item structure
  367. gFiles.spec  (gFileIndex) = fSpec// save the item FSSpec
  368.  
  369. Long If Fn BitTst (pb.ioFlAttrib%, _kFolderBit)// Is it a folder?
  370.  // it's a folder...
  371. gFiles.type   (gFileIndex)  = _"fldr"// set the file type
  372. gFiles.creator(gFileIndex)  = _"----"// set the creator code
  373.  
  374. tpSpec.vRefNum = pb.ioVRefNum%// fill a temporary FSSpec structure 
  375. tpSpec.parID   = pb.ioDirID&// store the dirID of the parent folder in the structure...
  376. tpSpec.parID   = Fn GetFolderDirID( fSpec, _kDontCreateFolder )// to convert it to the dirID of the new folder we want to scan
  377.  
  378. Fn CollectFileItems( tpSpec, gFileIndex )// start another round with that folder
  379.  
  380. xelse// it is a file...
  381.  
  382. gFiles.type   (gFileIndex) = pb.ioFlUsrWds.fdType&// grab the info from the param block
  383. gFiles.creator(gFileIndex) = pb.ioFlUsrWds.fdCreator&
  384. gFiles.flags  (gFileIndex) = pb.ioFlUsrWds.fdFlags%
  385. gFiles.dataLen(gFileIndex) = pb.ioFlLgLen&
  386. gFiles.rsrcLen(gFileIndex) = pb.ioFlRLgLen&
  387. gFiles.cDate  (gFileIndex) = pb.ioFlCrDat&
  388. gFiles.mDate  (gFileIndex) = pb.ioFlMdDat&
  389. gFiles.attrib (gFileIndex) = pb.ioFlAttrib%
  390. End If
  391.  
  392. End If
  393.  
  394. index++// next file or folder in the current folder
  395.  
  396. Until _nil
  397.  
  398. End Fn
  399.  
  400.  
  401. '~-----
  402. '~DataBrowser Setting & Getting Data
  403. '~'1
  404. /*
  405.      This function is called via a callback procedure. This is
  406.      the only required routine to work with a DataBrowser control.
  407.      The DataBrowser asks you to setup some values for the cells
  408.      that it must display. Those values are set with specific functions
  409.      depending on the type of the cell to be updated.
  410.      With the same callback routine the DataBrowser may inform you
  411.      that a cell has been changed by the end user, so it is time
  412.      to get the value sent by the DataBrowser to update your
  413.      internal information.
  414. */
  415. Clear Local Fn MyGetSetItemData( browser As ControlRef, itemID As DataBrowserItemID, columnPropID As DataBrowserPropertyID, itemData As DataBrowserItemDataRef, userChangedItemData As Boolean )
  416. '~'9
  417. Dim As OSStatus    err
  418. Dim As CFStringRef txt
  419. Dim As IconRef     iconH
  420. Dim As FSSpec      fSpec : fSpec = gFiles.spec(itemID)// copy info from the dynamic array...
  421. Dim As OSType      fType : fType = gFiles.type(itemID)// ... in local variables
  422. Dim As OSType      fCrea : fCrea = gFiles.creator(ItemID)
  423.  
  424. err = _noErr
  425.  
  426. Long If userChangedItemData = _false
  427.  
  428. Select columnPropID
  429.  
  430. Case _nameColumnID' names and icons
  431.  
  432. iconH = Fn GetFileIcon( fSpec, ftype )
  433. Long If iconH
  434. err = Fn SetDataBrowserItemDataIcon( itemData, iconH )
  435. err = Fn ReleaseIconRef(iconH)
  436. End If
  437.  
  438. txt = Fn CFStringCreateWithPascalString( Fn CFAllocatorGetDefault, fSpec.name, _kCFStringEncodingMacRoman )
  439. err = Fn SetDataBrowserItemDataText( itemData, txt ) : CFRelease( txt )
  440.  
  441. Case _typeColumnID, _creatorColumnID// file type and creator code columns
  442.  
  443. Long If fType != _"fldr"// skip folders
  444. Select columnPropID
  445. Case _typeColumnID    : txt = fType// deal with Type column
  446. Case _creatorColumnID : txt = fCrea// deal with Creator column
  447. Case else             : txt = 0
  448. End Select
  449. txt = Fn CFStringCreateWithPascalString( Fn CFAllocatorGetDefault, mki$(txt), _kCFStringEncodingMacRoman )
  450. err = Fn SetDataBrowserItemDataText( itemData, txt ) : CFRelease( txt )
  451. End If
  452.  
  453. Case _kDataBrowserItemIsContainerProperty// is that item a container?
  454.  
  455. err = Fn SetDataBrowserItemDataBooleanValue( itemData, (fType = _"fldr") )// answer true if the item is a folder
  456.  
  457. Case else:
  458.  
  459. err = _errDataBrowserPropertyNotSupported
  460.  
  461. End Select
  462.  
  463. xelse
  464. /*
  465.      The end user has altered the cell if we come here.
  466.      For testing with the color column
  467. */
  468. err = _errDataBrowserPropertyNotSupported
  469.  
  470. End If
  471.  
  472. End Fn = err
  473.  
  474.  
  475. /*
  476.      This function called by the ItemNotification callback procedure
  477.      will receive some interesting message coming from the DataBrowser.
  478.      For our purpose, we are interested to know when a container is
  479.      opened so that we can add the appropriate subItems.
  480. */
  481. Clear Local Fn MyItemNotification( browser As ControlRef, itemID As DataBrowserItemID, message As DataBrowserItemNotification )
  482. '~'9
  483. Dim As OSStatus            err
  484. Dim As UInt32              i, numItems
  485. Dim As DataBrowserItemID @ childItemID
  486. Dim As Handle              subItems
  487.  
  488. Select message
  489.  
  490. Case _kDataBrowserContainerOpened:// a container has been opened
  491.  
  492. subItems = Fn NewHandle( 0 )// we will prepare our array of subItems in a handle
  493. If subItems = _nil then Exit Fn
  494.  
  495. numItems = Fn UBound(gFiles)// retrieve the item count in our dynamic array
  496. /*
  497.      Below we start the loop at 2 'cos we don't use index 0 for our
  498.      dynamic array, neither index 1 since the latter is reserved for
  499.      the folder chosen by the end-user and we don't want it to appear
  500.      in the list.
  501. */
  502. For i = 2 To numItems
  503. Long If gFiles.parent(i) = itemID// if the parent itemID of that item is the itemID of the opened container
  504. childItemID = gFiles.itemID(i)// we can append that item (its itemID) to our list
  505. Long If Fn PtrAndHand( @childItemID, subItems, Sizeof(DataBrowserItemID) ) != _noErr
  506. DisposeHandle( subItems ) : subItems = _nil : Exit Fn// clean up the memory if an error occurs
  507. End If
  508. End If
  509. Next
  510.  
  511. HLock( subItems )// now we can add the itemIDs in the DataBrowser control
  512. err = Fn AddDataBrowserItems( browser, itemID, Fn GetHandleSize( subItems ) \\ Sizeof(DataBrowserItemID) , #[subItems], _kDataBrowserOrderDecreasing )
  513. HUnlock( subItems )
  514. DisposeHandle( subItems )
  515.  
  516. Case _kDataBrowserSelectionSetChanged:
  517.  
  518. End Select
  519.  
  520. End Fn
  521.  
  522. '~-------
  523. '~DataBrowser Installing
  524. '~';
  525. /*
  526.      This function creates the DataBrowser. It will
  527.      size the DataBrowser control to match the content
  528.      area of the window, then remove the automatic
  529.      focus ring of the DataBrowser.
  530. */
  531. Clear Local Fn CreateDataBrowser( wRef As WindowRef )
  532. '~'9
  533. Dim As Rect         r
  534. Dim As ControlRef @ browser
  535. Dim As Boolean    @ frameAndFocus
  536.  
  537. Long If Fn GetWindowBounds( wRef, _kWindowContentRgn, r ) = _noErr
  538. OffsetRect( r, -r.left, -r.top )
  539. Long If Fn CreateDataBrowserControl( wRef, r, _kDataBrowserListView, browser ) = _noErr
  540. // Turn off DB's focus frame
  541. Long If Fn SetControlData( browser, _kControlNoPart, _kControlDataBrowserIncludesFrameAndFocusTag, Sizeof(frameAndFocus), frameAndFocus )
  542. End If
  543. End If
  544. End If
  545.  
  546. End Fn = browser
  547.  
  548. '~';
  549. /*
  550.      This function sets all the callback procedures that the DataBrowser
  551.      will use in this demo to communicate with the program.
  552.      There is a bunch of  callback routines available for the customization
  553.      of the DataBrowser control. Here, we use the only two which are
  554.      required to display a hierarchical list.
  555. */
  556. Clear Local Fn InstallDataBrowserCallbacks( browser As ControlRef )
  557. '~'9
  558. Dim As OSStatus               err
  559. Dim As DataBrowserCallbacks @ myCallbacks
  560.  
  561. myCallbacks.version = _kDataBrowserLatestCallbacks//Use latest layout and callback signatures
  562.  
  563. err = Fn InitDataBrowserCallbacks( myCallbacks )
  564. myCallbacks.u.itemDataCallback         = Fn NewDataBrowserItemDataUPP         ( [Proc "GetSetItemDataProc"   + _FBprocToProcPtrOffset] )
  565. myCallbacks.u.itemNotificationCallback = Fn NewDataBrowserItemNotificationUPP ( [Proc "ItemNotificationProc" + _FBprocToProcPtrOffset] )
  566. err = Fn SetDataBrowserCallbacks( browser, myCallbacks )
  567.  
  568. End Fn
  569.  
  570.  
  571. /*
  572.      The two functions below iare meant to simplify
  573.      the code, allowing to avoid cumbersome statements
  574. */
  575. '~'1
  576.  
  577. /*
  578.      After creating the DataBrowser, you need to configure it.
  579.      That is to say to define columns and their properties.
  580.      Here are the column property types you can use:
  581.  
  582.           constant names                 cell's contents are set with
  583.      _kDataBrowserCustomType        No associated data (must use custom callbacks)
  584.      _kDataBrowserIconType          IconRef, IconTransformType, RGBColor 
  585.      _kDataBrowserTextType          CFStringRef
  586.      _kDataBrowserDateTimeType      DateTime or LongDateTime
  587.      _kDataBrowserSliderType        Min, Max, Value
  588.      _kDataBrowserCheckboxType      ThemeButtonValue
  589.      _kDataBrowserProgressBarType   Min, Max, Value
  590.      _kDataBrowserRelevanceRankType Min, Max, Value
  591.      _kDataBrowserPopupMenuType     MenuRef, Value
  592.      _kDataBrowserIconAndTextType   IconRef, CFStringRef, etc 
  593.  
  594. */
  595. Clear Local Mode
  596. Local Fn SetupColumn(        column As .DataBrowserListViewColumnDesc, ┬
  597.                         columnID As UInt32, ┬
  598.                   columnProperty As DataBrowserPropertyType, ┬
  599.                      columnTitle As Str255, ┬
  600.                      columnFlags As DataBrowserPropertyFlags, ┬
  601.                    headerContent As SInt16, ┬
  602.                         minWidth As UInt16, ┬
  603.                         maxWidth As UInt16 )
  604. '~'9
  605.  
  606. column.propertyDesc.propertyID    = columnID
  607. column.propertyDesc.propertyType  = columnProperty
  608. column.propertyDesc.propertyFlags = columnFlags
  609.  
  610. column.headerBtnDesc.btnContentInfo.contentType = headerContent
  611. column.headerBtnDesc.minimumWidth               = minWidth
  612. column.headerBtnDesc.maximumWidth               = maxWidth
  613. column.headerBtnDesc.titleString = Fn CFStringCreateWithPascalString( Fn CFAllocatorGetDefault, columnTitle, _kCFStringEncodingMacRoman )
  614.  
  615. End Fn
  616.  
  617.  
  618. '~'9
  619. /*
  620.      SetupColumnHeaderStyle( column, font, size, face, mode,just )
  621.  
  622.      column     : a column descriptor
  623.  
  624.      font       : font ID used in the header button or the old contants:
  625.                     _sysfont    _london       _times
  626.                     _applfont   _athens       _helvetica
  627.                     _newyork    _sanfran      _courier
  628.                     _geneva     _toronto      _symbol
  629.                     _monaco     _cairo        _mobile
  630.                     _venice     _losangeles   _apfontid
  631.  
  632.      size      : font size in pixels
  633.  
  634.      face      : font style. Use the following constants:
  635.                     _boldBit%    _ulineBit%    _shadowBit%     
  636.                     _italicBit%  _outlineBit%  _condenseBit%
  637.                       
  638.      mode      : transfer mode. Try:
  639.                     _srcCopy       _notSrcCopy  _patCopy  _notPatCopy
  640.                     _srcOr         _notSrcOr    _patOr    _notPatOr
  641.                     _srcXor        _notSrcXor   _patXor   _notPatXor
  642.                     _srcBic        _notSrcBic   _patBic   _notPatBic                                 
  643.                     _hilite        _blend              
  644.                     _addPin        _addOver
  645.                     _subPin        _addMax
  646.                     _adMax         _subOver
  647.                     _adMin         _ditherCopy
  648.                     _transparent   _grayishTextOr
  649.                     _hilitetransfermode
  650.  
  651.      just     : text justification. Use:
  652.                     _teJustLeft     _teFlushDefault
  653.                     _teJustCenter   _teCenter
  654.                     _teJustRight    _teFlushRight
  655.                     _teForceLeft    _teFlushLeft
  656. */
  657.  
  658. Clear Local Mode
  659. Local Fn SetupColumnHeaderStyle( column As ^DataBrowserListViewColumnDesc, ┬
  660.                                font As Short, ┬
  661.                                size As Short, ┬
  662.                                face As Short, ┬
  663.                                mode As Short, ┬
  664.                                just As Short )
  665. '~'9
  666. Dim colStyle As ControlFontStyleRec
  667.  
  668. colStyle = column.headerBtnDesc.btnFontStyle
  669. If font then colStyle.flags = colStyle.flags Or _kControlUseFontMask : colStyle.font  = font
  670. If size then colStyle.flags = colStyle.flags Or _kControlUseSizeMask : colStyle.size  = size
  671. If face then colStyle.flags = colStyle.flags Or _kControlUseFaceMask : colStyle.style = face
  672. If mode then colStyle.flags = colStyle.flags Or _kControlUseModeMask : colStyle.Mode  = mode
  673. If just then colStyle.flags = colStyle.flags Or _kControlUseJustMask : colStyle.just  = just
  674. BlockMoveData( @colStyle, @column.headerBtnDesc.btnFontStyle, Sizeof(ControlFontStyleRec) )
  675. End Fn
  676.  
  677.  
  678. /*
  679.      This function will add the columns in the DataBrowser control
  680. */
  681. Clear Local Fn ConfigureDataBrowser( browser As ControlRef )
  682. '~'9
  683. Dim As OSStatus                       err
  684. Dim As DataBrowserListViewColumnDesc  col
  685. Dim As DataBrowserViewStyle         @ viewStyle
  686.  
  687. err = Fn GetDataBrowserViewStyle( browser, viewStyle )
  688.  
  689. Select viewStyle
  690.  
  691. Case _kDataBrowserListView:
  692.  
  693. col.headerBtnDesc.titleOffset = 0
  694. col.headerBtnDesc.version     = _kDataBrowserListViewLatestHeaderDesc
  695.  
  696. /*
  697.      Two custom functions for easy setup
  698.  
  699.      fn SetupColumn( columnDescriptor,┬
  700.                              columnID, ┬
  701.                        columnProperty, ┬
  702.                           columnTitle, ┬
  703.                           columnFlags, ┬
  704.                         headerContent, ┬
  705.                              minWidth, ┬
  706.                              maxWidth )
  707.  
  708.      fn SetupColumnHeaderStyle( columnDescriptor, fontID, textSize, textFace, textMode,justification )
  709. */
  710.  
  711. // ------- Add the name & icon column ------- 
  712. Fn SetupColumn(          col, ┬
  713.                _nameColumnID, ┬
  714. _kDataBrowserIconAndTextType, ┬
  715.                        "Name",┬
  716. _kDataBrowserListViewSelectionColumn_kDataBrowserListViewDefaultColumnFlags, ┬
  717.     _kControlContentTextOnly, ┬
  718.                       0 ,280 )
  719. Fn SetupColumnHeaderStyle( col, 0, 0, 0, 0, _teFlushDefault )
  720. err = Fn AddDataBrowserListViewColumn( browser, col, _kDataBrowserListViewAppendColumn )
  721.  
  722. // ------- Add the Creator Code column ------- 
  723. Fn SetupColumn(      col, ┬
  724.         _creatorColumnID, ┬
  725.    _kDataBrowserTextType, ┬
  726.                "Creator", ┬
  727. _kDataBrowserListViewSelectionColumn _kDataBrowserListViewDefaultColumnFlags, ┬
  728. _kControlContentTextOnly, ┬
  729.                     0 ,150 )
  730. Fn SetupColumnHeaderStyle( col, 0, 0, 0, 0, _teCenter )
  731. err = Fn AddDataBrowserListViewColumn( browser, col, _kDataBrowserListViewAppendColumn )
  732.  
  733. // ------- Add the File Type column ------- 
  734. Fn SetupColumn(     col, ┬
  735.           _typeColumnID, ┬
  736.   _kDataBrowserTextType, ┬
  737.                  "Type", ┬
  738. _kDataBrowserListViewSelectionColumn_kDataBrowserListViewDefaultColumnFlags, ┬
  739. _kControlContentTextOnly, ┬
  740.                   0 ,150 )
  741. err = Fn AddDataBrowserListViewColumn( browser, col, _kDataBrowserListViewAppendColumn)
  742.  
  743. // setup the disclosure column
  744. err = Fn SetDataBrowserListViewDisclosureColumn( browser, _nameColumnID, _false )
  745.  
  746. Case _kDataBrowserColumnView:
  747.  
  748. End Select
  749.  
  750. End Fn
  751.  
  752. '~';
  753. '~----
  754. '~Event Handling
  755. '~'1
  756. /*
  757.     This function is called via a menu Item.
  758. */
  759. Local Fn doOpenFolder 
  760. '~'9
  761.  
  762. Dim As int    err
  763. Dim As FSSpec fSpec
  764. Dim As Str255 name 
  765.  
  766. Long If Len( Files$( _FSSpecFolder, "Choose a folder",,fSpec ) )// select folder dialog
  767. Fn ClearDataBrowser// not cancelled, so clear the DataBrowser's content
  768. Kill Dynamic gFiles// dispose of the current dynamic array
  769. // set info for the first item (we won't display it)
  770. gFileIndex = 1// this will be our first item
  771. gFiles.itemID (gFileIndex) = gFileIndex// first itemID 
  772. gFiles.spec   (gFileIndex) = fSpec// copy the selected FSSpec
  773. gFiles.type   (gFileIndex) = _"fldr"// give a type
  774. gFiles.creator(gFileIndex) = _"----"// and a creator to that item
  775. err = Usr FSGetFolderName( fSpec, name )// retrieve the folder name since folder FSSpecs have an empty name
  776. gFiles.spec.name(gFileIndex) = name// store it in our item structure
  777. Window _mainWnd, name// update window title
  778. Fn CollectFileItems( fSpec, gFileIndex )// collect files and folders
  779. Compress Dynamic gFiles// optimize memory
  780. Fn FillDataBrowser// create the DataBrowser items with the grabbed info
  781. End If
  782.  
  783. End Fn
  784.  
  785. /*
  786.      Cheap menu handler
  787. */
  788. Local Fn doMenu
  789. '~'9
  790. Dim As Short menuID, itemID
  791.  
  792. menuID = Menu( _menuID )
  793. itemID = Menu( _ItemID )
  794.  
  795. Select menuID
  796. Case _menuFile
  797. Select itemID
  798. Case _itemOpenFolder : Fn doOpenFolder
  799. Case _itemQuit       : End
  800. End Select
  801. End Select
  802.  
  803. Menu
  804.  
  805. End Fn
  806.  
  807.  
  808. /*
  809.      Minimalist dialog handler
  810. */
  811. Local Fn doDialog
  812. '~'9
  813. Dim As Long act, ref
  814.  
  815. act = Dialog(0)
  816. ref = Dialog(act)
  817.  
  818. Select act
  819. Case _wndZoomIn, _wndZoomOut,_wndResized
  820. Fn RefreshDataBrowser( ref )
  821. Case _wndClose : End
  822. End Select
  823.  
  824. End Fn
  825.  
  826. '~';
  827. '~------
  828. '~Main Program
  829. '~';
  830. /*
  831.      This function installs our cheap menu, a window
  832.      and a DataBrowser control in that window.
  833.      It runs the main event loop too.
  834. */
  835. Clear Local Fn StartProgram
  836. '~'9
  837. Dim As OSStatus        err
  838. Dim As Rect            r
  839. Dim As WindowRef     @ wRef
  840. Dim As ControlRef    @ browser
  841.  
  842. // Setup a menu
  843. Menu _menuFile,  0             , _enable, "File"
  844. Menu _menuFile, _itemOpenFolder, _enable, "Open Folder/O"
  845. Menu _menuFile, _itemQuit      , _enable, "Quit/Q"
  846.  
  847. // Setup a window
  848. SetRect( r, 100, 100, 600, 400 )
  849. Appearance Window - _mainWnd, "Hierarchical DataBrowser", @r ,_kDocumentWindowClass, ┬
  850.                     _kWindowInWindowMenuAttribute _kWindowStandardDocumentAttributes
  851.                                                                                                
  852. wRef = Window( _wndRef )
  853. err = Fn SetAutomaticControlDragTrackingEnabledForWindow( wRef, _true )
  854.  
  855. // Create the DataBrowser control
  856. browser = Fn CreateDataBrowser( wRef )
  857.  
  858. Long If browser
  859. Fn InstallDataBrowserCallbacks( browser )// install the callback routines
  860. Fn ConfigureDataBrowser( browser )// Configure the DataBrowser
  861. err = Fn SetKeyboardFocus( wRef, browser, _kControlDataBrowserPart )// Set the keyboard focus
  862. err = Fn SetWindowProperty( wRef, _myCreator, _myDataBrowser, Sizeof(browser), browser )// Store our custom DataBrowser ID as a window property
  863. End If
  864.  
  865. Window _mainWnd// make the window visible
  866.  
  867. On Menu   Fn doMenu
  868. On Dialog Fn doDialog
  869.  
  870. Do
  871. Handleevents
  872. Until _nil
  873.  
  874. End Fn
  875.  
  876. // The start
  877. Fn StartProgram
  878.  
  879. '~---
  880. '~Applications Proc
  881. /*
  882.      Entry points for the callback procedures (will be redirected to local fns)
  883. */
  884. #If Def _FBUseDebugger
  885. Troff
  886. #Endif
  887.  
  888. goto "skip procs"
  889.  
  890. "GetSetItemDataProc"
  891. Enterproc Fn GetSetItemDataProc( browser As ControlRef, itemID As DataBrowserItemID, prop As DataBrowserPropertyID, itemData As DataBrowserItemDataRef, changeValue As Boolean ) = OSStatus
  892. Exitproc = Fn MyGetSetItemData( browser, itemID, prop, itemData, changeValue )
  893.  
  894. "ItemNotificationProc"
  895. Enterproc ItemNotificationProc( browser As ControlRef, itemID As DataBrowserItemID, message As DataBrowserItemNotification )
  896. Fn MyItemNotification( browser, itemID, message )
  897. Exitproc
  898. "skip procs"
  899.  
  900. #If Def _FBUseDebugger
  901. Tron
  902. #Endif
  903.  
  904.